/*
 * Copyright (c) Huawei Device Co., Ltd. 2024. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "access_rule_cache.h"
#include "ara_controller.h"
#include "arf_manager.h"
#include "loghelper.h"
#include "ref_do.h"
#include "ar_do.h"
#include "ref_ar_do.h"
#include "apdu_ar_do.h"
#include "common_utils.h"

namespace OHOS {
namespace SE {
using namespace std;
std::shared_ptr<ResponseAllRefArDo> g_araResponseAllRefDo;
std::shared_ptr<ResponseAllRefArDo> g_arfResponseAllRefDo;
std::vector<struct StuAccessRules> g_exactAidAndAppIdRules;
std::vector<struct StuAidExactAccessRules> g_exactAidRules;
std::vector<struct StuAppIdExactAccessRules> g_exactAppIdRules;
bool g_isAllowedAll = false; // all aid and all appid

/*
* Compatible with old SIM cards that only pre-set the AC rule for other OS signature certificate.
* Other OS signature certificate never expires on system, but local signature certificate is valid for 1 year.
* key: APP other OS signature certificate.
* vector: can be signature certificate or APPID sha256. recommend APPID sha256.
*/
std::map<std::string, std::vector<std::string>> g_appSignatureMap = {
    {
        "E921C7B7171D8C610948CDF213E03DB1A9E05EC0",
        {
            // operator test env app id sha256
            "8820F1879F418E604C67C295C58DFB7685C5F614415E63A477D12BD6B63C2ED6",
            // operator release env old app id sha256
            "670699A0D126D392C7C79E17971FA207D8C1ED24A4D5677F1D5AA9E7F8C181D1",
            // operator release env new app id sha256
            "3385C85776B9A2C840189D58B1673B85A5A812B68D1DBBA6CA7831621181755F",
        }
    },
    {
        "4B1AD4123E03F524A4CD4AF8C944BA2ABADAFECB",
        {
            "51891303C49297BB0D461BC521B303AD4BF8BF8E31F2F2C20FF296B562539137",
        }
    },
    {
        // For com.hebnx.mbank.pmbank production environment
        "054EA65864293A0C72E3E8D3030AD2322422701C",
        {
            "5D372AFA1B69B0684B0CD51D5F4997845A6E1668C7DC0642C39829CBFA4320BA",
            "834FFEDCBCE718F5B95724ADE23DAF4B31E3A59D50FFE3FF4077867E651C0447",
            "8883D1821B3413B54BD61482B9DF0721AA3FB7C8C7FF51E935785739256BB9B2",
            // com.hebnx.mbank.hpmbank
            "07B432F1C2FC216117C9E6EBC6A70555C52646C3FABD51CD9B938061511D4F82",
            // com.hebnx.mbank.hembank
            "F8EFCB377CD805A2475E81D1C0BAAFC46C2745A0E9ACA8C6826E11E4297CD1F0"
        }
    },
    {
        "FDE6EE9FE7488C849072A2E1747C1382BEE9B86F",
        {
            "8F93DA00C0DF38B0EED35D4C9ACB1BCEB4F4383CBE7AB0E8CE4717E45301F461",
        }
    },
    {
        "F66D73EF560DE10297DE05656E8575E75F42B7CD",
        {
            "33F48C533C6A1F438BC18D094BC4A4C231B97E49BF94595E9AB183E5268FA705",
            "3B9F4E95941E169DA8AC61E0167E803C43683F98FCDFAB452DA1B571ADFBCD52",
        }
    },
    {
        "78FD718E0F85C952D21898F25D15AA845C87F1D3",
        {
            "33F48C533C6A1F438BC18D094BC4A4C231B97E49BF94595E9AB183E5268FA705",
            "3B9F4E95941E169DA8AC61E0167E803C43683F98FCDFAB452DA1B571ADFBCD52",
        }
    },
    { // China Mobile test environment mapping
        "9BD5B5590EB17981E0D39307DF62678DF8FFE292",
        {
            "E4D8DA2395B0E416699EDFF3D0489852D266594D",
            "588C802A3732359E0DB7585773F162510769FB09D89AE5D20404C41EED5C64C9",
            "57722F70A2813DFD1DBBEA44CD372353291DA8A9",
            "D9ECD91AD8925B904E88E414D531DC709B77A5AC4DE3139D23526C5B13F1CFA0",
            "41D648BA05BF87C724EF721C549A4F767D4A530E0748D2700EE16D196174297F",
        }
    },
    { // China Mobile release environment mapping
        "3CFB3A993DE5EE0F50B746F6F1B8F5A4AEFDF79A",
        {
            "E4D8DA2395B0E416699EDFF3D0489852D266594D",
            "588C802A3732359E0DB7585773F162510769FB09D89AE5D20404C41EED5C64C9",
            "57722F70A2813DFD1DBBEA44CD372353291DA8A9",
            "D9ECD91AD8925B904E88E414D531DC709B77A5AC4DE3139D23526C5B13F1CFA0",
            "0D65072F87D6B6DC8D4143825B9A3848F6FE5D577472195730979980D980E34E",
        }
    },
    { // For com.sinovatech.unicom.ha
        "A445549E3F550987D53B660D8B8FB701C94AE9BD",
        {
            "9970ECF9FD027ACE4F986E8B1B9E6A9512642151E3CD0C414E5EBD9C0F2CE540",
            "A2EA35E6D664E483B3AADFB29ECE03D55A145D61068B6547688E6CD856E633E1",
        },
    },
    { // For micronet guilin
        "F60EBF082D988B82396F6E08C1AD202A1ED4E53F",
        {
            "9657B11E76E5727E52C7BEA2A4FA05E378367D595ECD0AEF5B3BE9B1D84F4CB2",
        },
    },
    { // For com.micronet.gx
        "AA0D18C0C6F1DB127015518FAB27B34EE9CCA9CC",
        {
            "A781A7E2A4C489892AEDFBAE3D0AFE9352128B2EA25F6828507EA1964DFE6F50",
        },
    },
    { // For com.micronet.ln
        "4B1AD4123E03F524A4CD4AF8C944BA2ABADAFECB",
        {
            "10ACCD5814C593AACA6AC0D3D992C80BABCCE292F1C7FD00C6654B16A7293BD5",
        },
    },
    { // For com.micronet.hunan
        "31A1B8B625591CFBE68899DA389AC6ABDEDC46DA",
        {
            "6AA3568B632A5E5E728E23447D25386CE809C8EE3C7EA5F1200AE8ADCA3A83DB",
        },
    },
    { // For com.jlnx.mbank.hmos production environment
        "33CAD4B86DB956A6DFBB80C6CCFEE37150FDBC71",
        {
            "14583C89823E54F0120898C35A075291BEE035D3F92857FB68B6DF7FF5FDE7FE",
            "E3002BD150290566E15A6B89FC30622C799ABB72AD9F13BB95B460D8D4679650",
            "CDAA9EDC81908CCD4FACA78D7388F4766349AFE72ABDD2C22956D803D255F1F0",
            "4A970D3F4148671B372FAD0ECB9445E8BBC4BB20B526FA1A1E40D5EE9002DD15",
            "14BC676D4D90DE3388C4D4131BBDC99477AF5A853B42A1B13009EE787267160A"
        },
    },
    { // For com.nxy.bank.neimeng production environment
        "9CA029D5285E67592C36BCC473638E65B3F868C3",
        {
            "620D5757C2D3E51D7FBA5732F14C2E0FFE1C37891BBAB2130497338B4F728196",
            "C1D6D5653F448B90347383E36598970D06B3FD938FDAD4C5E8C2792E19E805CE"
        },
    },
    { // For com.hljnsh.perbank.hm && com.hljnsh.entbank.hm production environment
        "FDE6EE9FE7488C849072A2E1747C1382BEE9B86F",
        {
            // com.hljnsh.perbank.hm
            "8FEEC0E70277A4B01C7D99089E3D97423B97A0DA872CEC362DD99C3BA246AF32",
            // com.hljnsh.entbank.hm
            "D90E5FD1A3093677DF7CF96FA0AB98A9D5DEDC041B5903724E5BA89A1874FC91"
        },
    },
};

/*
 * Software that is part of the Secure Element access API, it obtains access
 * rules from the Secure Element and applies those rules to restrict device
 * application access to the various Secure Element applications.
 */
AccessRuleCache::AccessRuleCache(bool isAra, bool isArf, std::weak_ptr<SecureElementAgent> agent)
{
    isAra_ = isAra;
    isArf_ = isArf;
    agent_ = agent;
}

AccessRuleCache::~AccessRuleCache()
{
}

bool AccessRuleCache::GetAraResponseAllRefDo()
{
    bool ret = false;
    if (isAra_) {
        AraController tmpAraController = AraController(agent_);
        if (!tmpAraController.IsNeedRefresh()) {
            return true;
        }

        std::vector<uint8_t> responseData;
        if (tmpAraController.ReadAllAccessRules(responseData) != ErrorCode::SE_SUCCESS) {
            ErrorLog("fail to get ara access rules.");
            return false;
        }
        std::string responseStr = CommonUtils::BytesArrayToHexString(&responseData[0], responseData.size());
        InfoLog("responseStr = %{public}s", responseStr.c_str());
        g_araResponseAllRefDo = std::make_shared<ResponseAllRefArDo>(responseData);
        ret = ParseAraResponseAllRefArDo();
    }
    return ret;
}

bool AccessRuleCache::Initialize()
{
    std::vector<uint8_t> refreshTag;
    bool ret = true;
    InfoLog("isAra_ = %{public}d, isArf_ = %{public}d", isAra_, isArf_);
    ret = GetAraResponseAllRefDo();
    if (isArf_) {
        if (!ArfManager::GetInstance().Initialize(agent_)) {
            InfoLog("Maybe no need update arf access rules.");
            return true;
        }
        std::vector<std::shared_ptr<RefArDo>> arfRules = ArfManager::GetInstance().GetArfRule();
        std::vector<uint8_t> arfRespAllRefDoPayload;
        for (auto& it : arfRules) {
            if (it == nullptr) {
                continue;
            }
            std::vector<uint8_t> tempPayload;
            it->GetRawData(tempPayload);
            arfRespAllRefDoPayload.insert(arfRespAllRefDoPayload.end(), tempPayload.begin(), tempPayload.end());
        }
        g_arfResponseAllRefDo = std::make_shared<ResponseAllRefArDo>(arfRespAllRefDoPayload, true);
        std::vector<RefArDo> refArDoVec;
        g_arfResponseAllRefDo->GetRefArDo(refArDoVec);
        ret = ParseArfResponseAllRefArDo();
    }
    return ret;
}

bool AccessRuleCache::GetValueByArDo(ArDo &arDoIn, uint32_t &value)
{
    vector<ApduArDo> retApduArDo;
    if (!arDoIn.GetApduArDo(retApduArDo)) {
        value = APDU_DENIED;
        return true;
    }
    if (retApduArDo.empty()) {
        value = APDU_DENIED;
        return true;
    }
    if (retApduArDo.size() == 1) { // only one ApduArDo, only Apdu access not apdu filter
        vector<uint8_t> payload;
        if (!retApduArDo[0].GetDoPayload(payload)) {
            value = APDU_DENIED;
            return true;
        }
        if (payload.size() == 1) {
            value = (payload[0] == 1) ? APDU_ALLOWED : APDU_DENIED;
            return true;
        }
    }
    value = APDU_DENIED;
    return true;
}

bool AccessRuleCache::GetStuAccessRulesByRefDo(RefDo &refDoIn, StuAccessRules &retStuAccessVal)
{
    return true;
}

// parse refarado
bool AccessRuleCache::ParseAraResponseAllRefArDo()
{
    if (g_araResponseAllRefDo == nullptr) {
        ErrorLog("g_araResponseAllRefDo is null");
        return false;
    }
    vector<RefArDo> retRefArDo;
    if (!g_araResponseAllRefDo->GetRefArDo(retRefArDo) || retRefArDo.empty()) {
        ErrorLog("no ara access rules.continue to find arf");
    }
    for (auto it = retRefArDo.begin(); it != retRefArDo.end(); it++) {
        std::shared_ptr<RefArDo> tmpRetRefArDo = std::make_shared<RefArDo>(*it);
        if (tmpRetRefArDo == nullptr) {
            ErrorLog("create refardo failed");
            continue;
        }
        vector<RefDo> retRefDo;
        vector<ArDo> retArDo;
        struct StuAccessRules tmpStuAccessRules;
        struct StuAidExactAccessRules tmpStuExactAidAcRules;
        struct StuAppIdExactAccessRules tmpStuExactAppIdAcRules;
        uint8_t accessEnumFlags;
        if (!tmpRetRefArDo->GetRefDoAndArDo(retRefDo, retArDo)) {
            WarnLog("get refdo and ardo failed");
            continue;
        }
        if (retRefDo.empty() || retArDo.empty()) {
            WarnLog("error to get refdo and ardo");
            continue;
        }
		// get addId and aid by refDo
        std::vector<AidRefDo> retAidRefDo;
        std::vector<DeviceAppIdRefDo> retAppIdDo;
        if (retRefDo[0].GetAidRefDoAndDeviceAppDo(retAidRefDo, retAppIdDo)) {
            WarnLog("success to get aidrefdo and appiddo, continue to find ardo");
            if (retAidRefDo.empty() && retAppIdDo.empty()) {
                WarnLog("invalid aidrefdo and appiddo, continue to find other refardo");
                continue;
            }
            std::vector<uint8_t> tmpAid;
            std::vector<uint8_t> tmpString;
            std::string tmpAppId;
            if (!retAidRefDo[0].GetDoPayload(tmpAid)) {
                WarnLog("error to get aid");
            }
            if (!retAppIdDo[0].GetDoPayload(tmpString)) {
                WarnLog("error to get tmpString");
            }
            tmpAppId = CommonUtils::BytesArrayToHexString(&tmpString[0], tmpString.size());
            std::map<std::string, std::vector<uint8_t>> tmpMap;
            tmpMap[tmpAppId] = tmpAid;
            tmpStuAccessRules.mapAidAppId = tmpMap;
            accessEnumFlags = EXACT_AID_DEVICEAPP;
            goto GetArDo;
        }
        if (retRefDo[0].GetAidRefDo(retAidRefDo)) {
            InfoLog("success to get aidrefdo, continue to find ardo");
            std::vector<uint8_t> tmpAid;
            if (!retAidRefDo.empty() && retAidRefDo[0].GetDoPayload(tmpAid)) {
                tmpStuExactAidAcRules.aid = tmpAid;
                accessEnumFlags = EXACT_AID_ONLY;
                goto GetArDo;
            } else {
                WarnLog("invalid aidrefdo, continue to find other refardo");
                continue;
            }
        }
        if (retRefDo[0].GetDeviceAppDo(retAppIdDo)) {
            InfoLog("success to get appiddo, continue to find ardo");
            std::vector<uint8_t> tmpString;
            if (!retAppIdDo.empty() && retAppIdDo[0].GetDoPayload(tmpString)) {
                std::string tmpAppId = CommonUtils::BytesArrayToHexString(&tmpString[0], tmpString.size());
                tmpStuExactAppIdAcRules.deviceAppId = tmpAppId;
                accessEnumFlags = EXACT_DEVICEAPP_ONLY;
                goto GetArDo;
            } else {
                WarnLog("invalid aidrefdo and appiddo, continue to find other refardo");
                continue;
            }
        }
    GetArDo:
        std::vector<ApduArDo> retApduArDo;
        uint8_t accessRuleVal;
        if (retArDo[0].GetApduArDo(retApduArDo)) {
            if (retApduArDo.empty()) {
                ErrorLog("failed to get ApduArDo, try to nfcardo or permardo");
                return false; // todo nfc ardo and permardo
            }
            std::vector<uint8_t> tmpVal;
            if (!retApduArDo[0].GetDoPayload(tmpVal)) {
                ErrorLog("failed to get apdu val, try to nfcardo or permardo");
                return false; // todo nfc ardo and permardo
            }
            accessRuleVal = tmpVal[0];
        }
        switch (accessEnumFlags) {
            case EXACT_AID_DEVICEAPP:
                tmpStuAccessRules.accessVal = accessRuleVal;
                g_exactAidAndAppIdRules.push_back(tmpStuAccessRules);
                break;
            case EXACT_AID_ONLY:
                tmpStuExactAidAcRules.accessVal = accessRuleVal;
                g_exactAidRules.push_back(tmpStuExactAidAcRules);
                break;
            case EXACT_DEVICEAPP_ONLY:
                tmpStuExactAppIdAcRules.accessVal = accessRuleVal;
                g_exactAppIdRules.push_back(tmpStuExactAppIdAcRules);
                break;
            case EXACT_NONE:
                break;
            default:
                break;
        }
    }
    return true;
}

bool AccessRuleCache::GetArfAidAndAppId(RefDo &inRefDo, struct StuAccessRules &outStuAccessRules,
    uint8_t &accessEnumFlags)
{
    std::vector<AidRefDo> retAidRefDo;
    std::vector<DeviceAppIdRefDo> retAppIdDo;
    if (inRefDo.GetAidRefDoAndDeviceAppDo(retAidRefDo, retAppIdDo)) {
        InfoLog("success to get aidrefdo and appiddo, continue to find ardo");
        if (retAidRefDo.empty() && retAppIdDo.empty()) {
            ErrorLog("invalid aidrefdo and appiddo, continue to find other refardo");
            return false;
        }
        std::vector<uint8_t> tmpAid;
        std::vector<uint8_t> tmpString;
        std::string tmpAppId;
        if (!retAidRefDo.empty()) {
            if (!retAidRefDo[0].GetDoPayload(tmpAid)) {
                ErrorLog("error to get aid");
                return false;
            }
        }
        if (!retAppIdDo.empty()) {
            if (!retAppIdDo[0].GetDoPayload(tmpString)) {
                ErrorLog("error to get tmpString");
                return false;
            }
        }
        if (!tmpString.empty()) {
            tmpAppId = CommonUtils::BytesArrayToHexString(&tmpString[0], tmpString.size());
            std::map<std::string, std::vector<uint8_t>> tmpMap;
            tmpMap[tmpAppId] = tmpAid;
            outStuAccessRules.mapAidAppId = tmpMap;
            accessEnumFlags = EXACT_AID_DEVICEAPP;
            return true;
        }
    }
    return false;
}

bool AccessRuleCache::GetArfExactAid(RefDo &inRefDo, struct StuAidExactAccessRules &outStuExactAidAcRules,
    uint8_t &accessEnumFlags)
{
    std::vector<AidRefDo> retAidRefDo;
    if (inRefDo.GetAidRefDo(retAidRefDo)) {
        InfoLog("success to get aidrefdo, continue to find ardo");
        if (retAidRefDo.empty()) {
            ErrorLog("invalid aidrefdo, continue to find other refardo");
            return false;
        }
        std::vector<uint8_t> tmpAid;
        if (!retAidRefDo[0].GetDoPayload(tmpAid)) {
            ErrorLog("error to get aid");
            return false;
        }
        outStuExactAidAcRules.aid = tmpAid;
        accessEnumFlags = EXACT_AID_ONLY;
        return true;
    }
    return false;
}

bool AccessRuleCache::GetArfExactDeviceAppIdDo(RefDo &inRefDo,
    struct StuAppIdExactAccessRules &outStuExactAppIdAcRules, uint8_t &accessEnumFlags)
{
    std::vector<DeviceAppIdRefDo> retAppIdDo;
    if (inRefDo.GetDeviceAppDo(retAppIdDo)) {
        InfoLog("success to get appiddo, continue to find ardo");
        if (retAppIdDo.empty()) {
            ErrorLog("invalid aidrefdo and appiddo, continue to find other refardo");
            return false;
        }
        std::vector<uint8_t> tmpString;
        std::string tmpAppId;
        if (!retAppIdDo[0].GetDoPayload(tmpString)) {
            ErrorLog("error to get tmpString");
        }
        if (!tmpString.empty()) {
            tmpAppId = CommonUtils::BytesArrayToHexString(&tmpString[0], tmpString.size());
            outStuExactAppIdAcRules.deviceAppId = tmpAppId;
            accessEnumFlags = EXACT_DEVICEAPP_ONLY;
            return true;
        }
    }
    return false;
}

bool AccessRuleCache::GetArfArDo(ArDo &inArDo, uint8_t &accessRuleVal)
{
    std::vector<ApduArDo> retApduArDo;
    if (inArDo.GetApduArDo(retApduArDo)) {
        if (retApduArDo.empty()) {
            ErrorLog("failed to get ApduArDo, try to nfcardo or permardo");
            return false; // todo nfc ardo and permardo
        }
        std::vector<uint8_t> tmpVal;
        if (!retApduArDo[0].GetDoPayload(tmpVal)) {
            ErrorLog("failed to get apdu val, try to nfcardo or permardo");
            return false; // todo nfc ardo and permardo
        }
        accessRuleVal = tmpVal[0];
        return true;
    }
    ErrorLog("is not ardo");
    return false;
}

bool AccessRuleCache::SaveArfAcRules(const uint8_t &accessEnumFlags, uint8_t accessRuleVal,
    struct StuAccessRules &inStuAccessRules, struct StuAidExactAccessRules &inStuExactAidAcRules,
    struct StuAppIdExactAccessRules &inStuExactAppIdAcRules)
{
    switch (accessEnumFlags) {
        case EXACT_AID_DEVICEAPP:
            inStuAccessRules.accessVal = accessRuleVal;
            g_exactAidAndAppIdRules.push_back(inStuAccessRules);
            break;
        case EXACT_AID_ONLY:
            inStuExactAidAcRules.accessVal = accessRuleVal;
            g_exactAidRules.push_back(inStuExactAidAcRules);
            break;
        case EXACT_DEVICEAPP_ONLY:
            inStuExactAppIdAcRules.accessVal = accessRuleVal;
            g_exactAppIdRules.push_back(inStuExactAppIdAcRules);
            break;
        case EXACT_NONE:
        default:
            break;
    }
    return true;
}

bool AccessRuleCache::IsArfAllowedAll(RefDo &inRefDo)
{
    uint32_t tag;
    InfoLog("enter.");
    if (!inRefDo.GetDoTag(tag) || tag != REF_DO_TAG) {
        ErrorLog("No REF_AR_DO tag = %{public}d.", tag);
        return false;
    }
    std::vector<uint8_t> payload;
    if (!inRefDo.GetDoPayload(payload)) {
        return false;
    }
    std::vector<uint8_t> allowedAllRules = {0x4F, 0x00, 0xC1, 0x00};
    if (payload == allowedAllRules) {
        return true;
    }
    return false;
}

// parse refarfdo
bool AccessRuleCache::ParseArfResponseAllRefArDo()
{
    std::lock_guard<std::mutex> lock(mutex_);
    g_isAllowedAll = false;
    if (g_arfResponseAllRefDo == nullptr) {
        return false;
    }
    vector<RefArDo> retRefArDo;
    if (!g_arfResponseAllRefDo->GetRefArDo(retRefArDo)) {
        InfoLog("no ara access rules.continue to find arf");
        if (retRefArDo.empty()) {
            return false;
        }
    }
    for (auto it = retRefArDo.begin(); it != retRefArDo.end(); it++) {
        std::shared_ptr<RefArDo> tmpRetRefArDo = std::make_shared<RefArDo>(*it);
        if (tmpRetRefArDo == nullptr) {
            ErrorLog("create refardo failed");
            continue;
        }
        vector<RefDo> retRefDo;
        vector<ArDo> retArDo;
        struct StuAccessRules tmpStuAccessRules;
        struct StuAidExactAccessRules tmpStuExactAidAcRules;
        struct StuAppIdExactAccessRules tmpStuExactAppIdAcRules;
        uint8_t accessEnumFlags;
        if (!tmpRetRefArDo->GetRefDoAndArDo(retRefDo, retArDo) || retRefDo.empty() || retArDo.empty()) {
            ErrorLog("get refdo and ardo failed");
            continue;
        }
        if (IsArfAllowedAll(retRefDo[0])) {
            g_isAllowedAll = true;
            WarnLog("allowed all aid and appid");
            return true;
        }
		// get addId and aid by refDo
        if (GetArfAidAndAppId(retRefDo[0], tmpStuAccessRules, accessEnumFlags)) {
            goto GetArDo;
        }
        ErrorLog("invalid aidrefdo and appiddo, continue to find other refardo");
        if (GetArfExactAid(retRefDo[0], tmpStuExactAidAcRules, accessEnumFlags)) {
            goto GetArDo;
        }
        ErrorLog("failed to get appiddo, continue to find ardo");
        if (GetArfExactDeviceAppIdDo(retRefDo[0], tmpStuExactAppIdAcRules, accessEnumFlags)) {
            goto GetArDo;
        }
        ErrorLog("failed to get appiddo, continue to find ardo");
    GetArDo:
        uint8_t accessRuleVal;
        if (!GetArfArDo(retArDo[0], accessRuleVal)) {
            ErrorLog("failed to get nfcardo or permardo");
            return false; // todo nfc ardo and permardo
        }
        SaveArfAcRules(accessEnumFlags, accessRuleVal, tmpStuAccessRules, tmpStuExactAidAcRules,
            tmpStuExactAppIdAcRules);
    }
    return true;
}

uint32_t AccessRuleCache::GetHmsFingerMap(const std::string &notHmsFingerKey, std::vector<std::string> &hmsFinger)
{
    auto iter = g_appSignatureMap.find(notHmsFingerKey);
    if (iter != g_appSignatureMap.end()) {
        hmsFinger = iter->second;
        return FINGER_MATCHED;
    }
    return NO_MATCHED;
}

bool AccessRuleCache::CompareAllFinger(const std::string &simFinger, const std::string &romFinger)
{
    if (simFinger == romFinger) {
        return true;
    }
    std::vector<std::string> hmsSimFinger;
    if (GetHmsFingerMap(simFinger, hmsSimFinger) != FINGER_MATCHED) {
        ErrorLog("no hms and non-hms map %{public}s", simFinger.c_str());
        return false;
    }
    size_t len = hmsSimFinger.size();
    for (size_t index = 0; index < len; index++) {
        if (hmsSimFinger[index] == romFinger) {
            InfoLog("match sim and rom finger %{public}s %{public}s", simFinger.c_str(), romFinger.c_str());
            return true;
        }
    }
    return false;
}

bool AccessRuleCache::IsAllowedByAidAndAppId(const std::vector<uint8_t> &aid, const std::string &appId,
    const std::string &fingerPrint, bool &accessRules)
{
    InfoLog("enter");
    bool allowed = false;
    for (auto it = g_exactAidAndAppIdRules.begin(); it != g_exactAidAndAppIdRules.end(); it++) {
        if (aid == (*it).mapAidAppId.begin()->second &&
            (appId == (*it).mapAidAppId.begin()->first || fingerPrint == (*it).mapAidAppId.begin()->first ||
            CompareAllFinger((*it).mapAidAppId.begin()->first, appId) ||
            CompareAllFinger((*it).mapAidAppId.begin()->first, fingerPrint))) {
            if ((*it).accessVal == 0) {
                accessRules = false;
                return true;
            }
            if ((*it).accessVal == 1) {
                allowed = true;
                break;
            }
        }
    }
    if (allowed) {
        accessRules = true;
        return true;
    }
    return false;
}

bool AccessRuleCache::IsAllowedByAidOnly(const std::vector<uint8_t> &aid, bool &accessRules)
{
    InfoLog("enter");
    bool allowed = false;
    for (auto it = g_exactAidRules.begin(); it != g_exactAidRules.end(); it++) {
        if (aid == (*it).aid) {
            if ((*it).accessVal == 0) {
                accessRules = false;
                return true;
            }
            if ((*it).accessVal == 1) {
                allowed = true;
            }
        }
    }
    if (allowed) {
        accessRules = true;
        return true;
    }
    return false;
}

bool AccessRuleCache::IsAllowedByAppIdOnly(const std::string &appId, const std::string &fingerPrint, bool &accessRules)
{
    InfoLog("enter");
    bool allowed = false;
    for (auto it = g_exactAppIdRules.begin(); it != g_exactAppIdRules.end(); it++) {
        if (appId == (*it).deviceAppId || fingerPrint == (*it).deviceAppId
            || CompareAllFinger((*it).deviceAppId, fingerPrint)) {
            if ((*it).accessVal == 0) {
                accessRules = false;
                return true;
            }
            if ((*it).accessVal == 1) {
                allowed = true;
            }
        }
    }
    if (allowed) {
        accessRules = true;
        return true;
    }
    return false;
}

bool AccessRuleCache::IsAllowed(
    const std::vector<uint8_t> &aid, const std::string &appId, const std::string &fingerPrint)
{
    std::string aidStr = CommonUtils::BytesArrayToHexString(&aid[0], aid.size());
    InfoLog("aid: %{public}s appId: %{public}s fingerPrint: %{public}s",
        aidStr.c_str(),
        appId.c_str(),
        fingerPrint.c_str());

    std::lock_guard<std::mutex> lock(mutex_);
    if (g_isAllowedAll) {
        InfoLog("IsAllowed return g_isAllowedAll");
        return true;
    }

    bool accessRules;
    if (IsAllowedByAidAndAppId(aid, appId, fingerPrint, accessRules)) {
        InfoLog("IsAllowedByAidAndAppId return true");
        return accessRules;
    } else if (IsAllowedByAidOnly(aid, accessRules)) {
        InfoLog("IsAllowedByAidOnly return true");
        return accessRules;
    } else if (IsAllowedByAppIdOnly(appId, fingerPrint, accessRules)) {
        InfoLog("IsAllowedByAppIdOnly return true");
        return accessRules;
    } else {
        ErrorLog("return false");
        return false;
    }
}

bool AccessRuleCache::IsAllowedByFingerPrint(const std::string &fingerPrint)
{
    return (fingerPrint == FINGER_PRINT_SHA256) || (fingerPrint == FINGER_PRINT_SHA1);
}
}  // namespace SE
}  // namespace OHOS

